import { browse, mapTree } from 'xe-utils';
import { camelCase, upperFirst } from 'lodash-es';
import { Message } from '@arco-design/web-vue';
import CronParser from 'cron-parser';
import { isExternal } from '@/utils/validate';

export function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
	return obj[key];
}

/**
 * @desc 去除空格
 * @param {string} str - 字符串
 * @param {string} pos - 去除空格的位置
 * pos="both": 去除两边空格
 * pos="left": 去除左边空格
 * pos="right": 去除右边空格
 * pos="all": 去除所有空格
 */
type Pos = 'both' | 'left' | 'right' | 'all';
export function trim(str: string, pos: Pos = 'both'): string {
	if (pos === 'both') {
		return str.replace(/^\s+|\s+$/g, '');
	} else if (pos === 'left') {
		return str.replace(/^\s*/, '');
	} else if (pos === 'right') {
		return str.replace(/(\s*$)/g, '');
	} else if (pos === 'all') {
		return str.replace(/\s+/g, '');
	} else {
		return str;
	}
}

/**
 * 根据数字获取对应的汉字
 * @param {number} num - 数字(0-10)
 */
export function getHanByNumber(num: number): string {
	const str = '零一二三四五六七八九十';
	return str.charAt(num);
}

/**
 * 获取指定整数范围内的随机整数
 * @param {number} start - 开始范围
 * @param {number} end - 结束范围
 */
export function getRandomInterger(start = 0, end: number): number {
	const range = end - start;
	return Math.floor(Math.random() * range + start);
}

/** @desc 千分位格式化 */
export function formatMoney(money: string) {
	return money.replace(new RegExp(`(?!^)(?=(\\d{3})+${money.includes('.') ? '\\.' : '$'})`, 'g'), ',');
}

/** @desc 数据类型检测方法 */
export function getTypeOf(value: any) {
	return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}

/**
 * @desc 格式化电话号码
  @demo 183-7983-6654 */
export function formatPhone(mobile: string, formatStr = '-') {
	return mobile.replace(/(?=(\d{4})+$)/g, formatStr);
}

/**
 * @desc 手机号脱敏
  @demo 155****8810  */
export function hidePhone(phone: string) {
	return phone.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2');
}

/** @desc 检测数据是否为空数据 */
export function isEmpty(data: unknown) {
	if (data === '' || data === 'undefined' || data === undefined || data == null || data === 'null') {
		return true;
	}
	return JSON.stringify(data) === '{}' || JSON.stringify(data) === '[]' || JSON.stringify(data) === '[{}]';
}

/**
 * @desc 大小写转换
 * @param {string} str 待转换的字符串
 * @param {number} type 1:全大写 2:全小写 3:首字母大写
 */
export function toCase(str: string, type: number) {
	switch (type) {
		case 1:
			return str.toUpperCase();
		case 2:
			return str.toLowerCase();
		case 3:
			return str[0].toUpperCase() + str.substring(1).toLowerCase();
		default:
			return str;
	}
}

/**
 * @desc 获取随机数
 * @param {number} min 最小值
 * @param {number} max 最大值
 */
export const randomNum = (min: number, max: number) => {
	return Math.floor(min + Math.random() * (max + 1 - min));
};

/**
  @desc 获取最大值 */
export const max = (arr: number[]) => {
	return Math.max.apply(null, arr);
};

/**
  @desc 获取最小值 */
export const min = (arr: number[]) => {
	return Math.min.apply(null, arr);
};

/**
  @desc 求和 */
export const sum = (arr: number[]) => {
	return arr.reduce((pre, cur) => pre + cur);
};

/**
  @desc 获取平均值 */
export const average = (arr: number[]) => {
	return sum(arr) / arr.length;
};

/**
  @desc 深拷贝 */
export const deepClone = (data: any) => {
	if (typeof data !== 'object' || data == null) return '不是对象';
	const newData: any = Array.isArray(data) ? [] : {};
	for (const key in data) {
		newData[key] = typeof data[key] === 'object' ? deepClone(data[key]) : data[key];
	}
	return newData;
};

/**
 * @desc 判断是否是闰年
 * @param {number} year 年份
 */
export const isLeapYear = (year: number) => {
	return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
};

/**
 * @desc 判断是否是奇数
 * @param {number} num 数字
 */
export const isOdd = (num: number) => {
	return num % 2 !== 0;
};

/**
 * @desc 判断是否是偶数
 * @param {number} num 数字
 */
export const isEven = (num: number) => {
	return !isOdd(num);
};

/**
  @desc 将RGB转化为十六机制 */
export const rgbToHex = (r: number, g: number, b: number) => {
	return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
};

/**
  @desc 获取随机十六进制颜色 */
export const randomHex = () => {
	return `#${Math.floor(Math.random() * 0xffffff)
		.toString(16)
		.padEnd(6, '0')}`;
};

/**
 * @description 动态路由 path 转 name
 * @demo /system => System
 * @demo /system/menu => SystemMenu
 * @demo /data-manage/detail => DataManageDetail
 */
export const transformPathToName = (path: string) => {
	if (!path) return '';
	if (isExternal(path)) return '';
	return upperFirst(camelCase(path));
};

/**
 * @desc 过滤树
 * @param { values } 数组
 */
type FilterTree = <T extends { children?: T[] }>(array: T[], iterate: (item: T, index?: number, items?: T[]) => boolean) => T[];
export const filterTree: FilterTree = (values, fn) => {
	const arr = values.filter(fn);
	const data = mapTree(arr, (item) => {
		if (item.children && item.children.length) {
			item.children = item.children.filter(fn);
		}
		return item;
	});
	return data;
};

type SortTree = <T extends { sort: number; children?: T[] }>(array: T[]) => T[];
/**
 * @desc 排序树
 * @param values /
 */
export const sortTree: SortTree = (values) => {
	values?.sort((a, b) => (a?.sort ?? 0) - (b?.sort ?? 0)); // 排序
	return mapTree(values, (item) => {
		item.children?.sort((a, b) => (a?.sort ?? 0) - (b?.sort ?? 0)); // 排序
		return item;
	});
};

/** @desc 是否是h5环境 */
export const isMobile = () => {
	return browse().isMobile;
};

/** @desc 问候 */
export function goodTimeText() {
	const time = new Date();
	const hour = time.getHours();
	return hour < 9 ? '早上好' : hour <= 11 ? '上午好' : hour <= 13 ? '中午好' : hour <= 18 ? '下午好' : '晚上好';
}

/** @desc 格式化文件大小 */
export const formatFileSize = (fileSize: number) => {
	if (fileSize == null || fileSize === 0) {
		return '0 Bytes';
	}
	const unitArr = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
	let index = 0;
	const srcSize = Number.parseFloat(fileSize.toString());
	index = Math.floor(Math.log(srcSize) / Math.log(1024));
	const size = srcSize / 1024 ** index;
	return `${size.toFixed(2)} ${unitArr[index]}`;
};

/** @desc 复制文本 */
export const copyText = (text: any) => {
	const textarea = document.createElement('textarea');
	textarea.value = text;
	document.body.appendChild(textarea);
	textarea.select();
	document.execCommand('copy');
	document.body.removeChild(textarea);
	Message.success('复制成功');
};

/** @desc 文件的转换base64 */
export const fileToBase64 = (file: File): Promise<string> => {
	return new Promise((resolve, reject) => {
		const reader = new FileReader();
		reader.onload = () => {
			if (reader.result) {
				resolve(reader.result.toString());
			} else {
				reject(new Error('文件转base64失败'));
			}
		};
		reader.onerror = (error) => {
			reject(error);
		};
		reader.readAsDataURL(file);
	});
};
export const YMD_HMS = 'yyyy-MM-dd HH:mm:ss';

/**
 * 格式化时间
 */
export function dateFormat(date = new Date(), pattern = YMD_HMS) {
	if (!date) {
		return '';
	}

	const o = {
		'M+': date.getMonth() + 1,
		'd+': date.getDate(),
		'H+': date.getHours(),
		'm+': date.getMinutes(),
		's+': date.getSeconds(),
		'q+': Math.floor((date.getMonth() + 3) / 3),
		'S+': date.getMilliseconds()
	};

	let formattedDate = pattern; // Start with the pattern

	// Year Handling
	const yearMatch = formattedDate.match(/(y+)/);
	if (yearMatch) {
		formattedDate = formattedDate.replace(yearMatch[0], `${date.getFullYear()}`.substring(4 - yearMatch[0].length));
	}

	// Other Formatters
	for (const k in o) {
		const reg = new RegExp(`(${k})`);
		const match = formattedDate.match(reg);
		if (match) {
			formattedDate = formattedDate.replace(match[0], match[0].length === 1 ? o[k] : `00${o[k]}`.substring(`${o[k]}`.length));
		}
	}

	return formattedDate;
}

/**
 * 不含年的 cron 表达式
 * @param cron
 */
const expressionNoYear = (cron: string) => {
	const vs = cron.split(' ');
	// 长度=== 7 包含年表达式 不解析
	if (vs.length === 7) {
		return vs.slice(0, vs.length - 1).join(' ');
	}
	return cron;
};

/**
 * 解析cron表达式预计未来运行时间
 * @param cron cron表达式
 */
export function parseCron(cron: string) {
	try {
		const parse = expressionNoYear(cron);
		const iter = CronParser.parseExpression(parse, {
			currentDate: dateFormat(new Date())
		});
		const result: string[] = [];
		for (let i = 1; i <= 5; i++) {
			const nextDate = iter.next();
			if (nextDate) {
				result.push(dateFormat(new Date(nextDate as any)));
			}
		}

		return result.length > 0 ? result.join('\n') : '无执行时间';
	} catch (e) {
		return '表达式错误';
	}
}
